package com.bzkj.document.utils.saleoutbound;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.bzkj.common.core.domain.entity.SysDictData;
import com.bzkj.common.domain.NccApiResponse;
import com.bzkj.document.enums.ProcessingType;
import com.bzkj.document.exception.WarehouseNotFoundException;
import com.bzkj.document.mapper.SalesOutboundMapper;
import com.bzkj.document.mapper.WmsWareHouseInventoryMapper;
import com.bzkj.document.utils.common.DataProcessUtils;
import com.bzkj.document.utils.common.InventoryManagerUtils;
import com.bzkj.system.service.ISysDictTypeService;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

@Component
public class SaleOutBoundUtils {
    @Resource
    private SalesOutboundMapper salesOutboundMapper;

    @Resource
    private InventoryManagerUtils inventoryManagerUtils;

    @Resource
    private WmsWareHouseInventoryMapper wareHouseInventoryMapper;

    @Resource
    private ISysDictTypeService sysDictTypeService;

    @Resource
    @Qualifier("threadPoolTaskExecutor")
    private ThreadPoolTaskExecutor executor;

    public List<Map<String, Object>> parsingSaleOutBounds(NccApiResponse nccApiResponse, int type, Boolean isConfirm) {
        JSONArray dataArray = nccApiResponse.getData() == null ? new JSONArray() : nccApiResponse.getData();

        List<CompletableFuture<Map<String, Object>>> futures = dataArray.stream().map(dataObject -> JSONObject.parseObject(JSONObject.toJSONString(dataObject))) // 显式转换为 JSONObject
                .map(dataObject -> CompletableFuture.supplyAsync(() -> processOrder(dataObject, type, isConfirm), executor)).collect(Collectors.toList());

        CompletableFuture<Void> allFutures = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));

        try {
            allFutures.get(); // 等待所有线程完成
        } catch (InterruptedException | ExecutionException e) {
            throw new RuntimeException("多线程解析订单时发生异常", e);
        }

        return futures.stream().map(CompletableFuture::join).filter(Objects::nonNull).collect(Collectors.toList());
    }

    private Map<String, Object> processOrder(JSONObject dataObject, int type, Boolean isConfirm) {
        JSONObject saleOutHead = dataObject.getJSONObject("ic.SaleOutHeadVO");
        if (saleOutHead == null) {
            return null; // 跳过缺少订单头的数据
        }
        Map<String, Object> saleOutHeadMap = parseSaleOutHead(saleOutHead);
        String vbillcode = saleOutHeadMap.get("vbillcode").toString();

        // 过滤销售出库单类型
        List<SysDictData> saleoutOrderAllow = sysDictTypeService.selectDictDataByType("saleout_order_allow");
        if (saleoutOrderAllow != null && !saleoutOrderAllow.isEmpty()) {
            if (saleoutOrderAllow.stream().noneMatch(dictData -> dictData.getDictValue().equals(saleOutHeadMap.get("vtrantypecode")) && "0".equals(dictData.getStatus()))) {
                return null;
            }
        }

        int isExist = salesOutboundMapper.selectIsExist(vbillcode);
        if (isExist > 0 && isConfirm) {
            return null;
        } else {
            saleOutHeadMap.put("isConfirm", 0);
        }

        JSONArray saleOutBodyList = dataObject.getJSONArray("ic.SaleOutBodyVO");
        if (saleOutBodyList == null || saleOutBodyList.isEmpty()) {
            return null; // 跳过没有订单行的数据
        }

        List<Map<String, Object>> details = parseSaleOutBodyList(saleOutBodyList, vbillcode, type, saleOutHeadMap);

        Map<String, Object> billData = new HashMap<>(2);
        billData.put("header", saleOutHeadMap);
        billData.put("details", details);

        return billData;
    }

    /**
     * 解析订单头数据
     *
     * @param header 订单头 JSON 对象
     * @return 订单头解析结果
     */
    private Map<String, Object> parseSaleOutHead(JSONObject header) {
        // 解析订单头逻辑
        return parseSaleOutHeadVO(header);
    }

    /**
     * 解析订单行数据列表
     *
     * @param saleOutBodyList 订单行 JSON 数组
     * @param vbillcode       单据编号
     * @param type            类型（0：查询，1：新增，2：修改）
     * @return 订单行解析结果列表
     */
    private List<Map<String, Object>> parseSaleOutBodyList(JSONArray saleOutBodyList, String vbillcode, int type, Map<String, Object> saleOutHeadMap) {
        List<Map<String, Object>> details = new ArrayList<>();
        List<Exception> exceptions = new ArrayList<>();
        for (int j = 0; j < saleOutBodyList.size(); j++) {
            JSONObject saleOutBody = saleOutBodyList.getJSONObject(j);
            // 调用解析方法
            Map<String, Object> detailMap = parsingsaleOutBodVO(saleOutBody);
            Object cwarehouseid = saleOutHeadMap.get("cwarehouseid");
            String vtrantypecode = saleOutHeadMap.get("vtrantypecode") == null ? "" : saleOutHeadMap.get("vtrantypecode").toString();
            if (type == ProcessingType.CONFIRM_ORDER.ordinal()) {
                try {
                    processWarehouseInfo(detailMap, cwarehouseid);
                } catch (Exception e) {
                    exceptions.add(e);
                }
            }

            detailMap.put("vbillcode", vbillcode);
            detailMap.put("cwarehouseid", cwarehouseid);
            detailMap.put("cgeneralhid", saleOutHeadMap.get("cgeneralhid").toString());
            detailMap.put("vtrantypecode", vtrantypecode);
            details.add(detailMap);
        }
        // 流处理完成后，统一处理异常
        if (!exceptions.isEmpty()) {
            // 可以记录日志、抛出聚合异常，或进行其他处理
            StringBuilder errorMessage = new StringBuilder();
            for (Exception exception : exceptions) {
                if (errorMessage.toString().isEmpty()) {
                    errorMessage.append("<ul>");
                }
                errorMessage.append(exception.getMessage());
            }
            throw new RuntimeException(errorMessage.append("</ul>").toString());
        }
        return details;
    }

    /***
     * 处理仓库信息
     * @param bodyMap 订单行数据
     * @param cwarehouseid NCC仓库信息
     */
    private void processWarehouseInfo(Map<String, Object> bodyMap, Object cwarehouseid) {
        String pkOrCode = DataProcessUtils.getPkOrCode(bodyMap, "cmaterialoid");
        @SuppressWarnings("unchecked") Map<String, Object> cmaterialoid = (Map<String, Object>) bodyMap.get("cmaterialoid");
        Object crowno = bodyMap.get("crowno");
        String warehousePk = DataProcessUtils.getPkOrCode((Map<String, Object>) cwarehouseid);
        List<HashMap<String, String>> warehouseList = inventoryManagerUtils.selectNccWarehouse(pkOrCode, warehousePk);
        if (warehouseList != null && !warehouseList.isEmpty()) {
            HashMap<String, String> hashMap = warehouseList.get(0);
            bodyMap.put("sto_id", hashMap.get("sto_id"));
            bodyMap.put("stu_class_id", hashMap.get("stu_class_id"));
        } else {
            String errorMsg = "<li>行号->" + crowno + "：物料名称：<b>" + cmaterialoid.get("name") + "<b>" + "在WMS系统中无法分配对应仓库！</li>";
            throw new WarehouseNotFoundException(errorMsg);
        }
    }

    /**
     * 解析ic.SaleOutHeadVO
     *
     * @param saleOutHeadVO JSONObject实体类
     * @return 解析后的数据
     */
    private HashMap<String, Object> parseSaleOutHeadVO(JSONObject saleOutHeadVO) {
        HashMap<String, Object> generalOutHeadMap = new HashMap<>(16);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

        // fbillflag(单据状态）
        DataProcessUtils.getStringField(saleOutHeadVO, "fbillflag", generalOutHeadMap);

        // cgeneralhid(表头主键）
        DataProcessUtils.getStringField(saleOutHeadVO, "cgeneralhid", generalOutHeadMap);

        // ctrantypeid(出入库类型）
        DataProcessUtils.getStringField(saleOutHeadVO, "ctrantypeid", generalOutHeadMap);

        // dmakedate（制单日期）
        DataProcessUtils.handleDateField(saleOutHeadVO, "dmakedate", sdf, generalOutHeadMap);

        // ccustomerid(订单客户)
        DataProcessUtils.processField(saleOutHeadVO, generalOutHeadMap, "ccustomerid");

        // csaleorgvid（销售组织）
        DataProcessUtils.processField(saleOutHeadVO, generalOutHeadMap, "csaleorgvid");

        // boutretflag（销售退回）
        DataProcessUtils.getStringField(saleOutHeadVO, "boutretflag", generalOutHeadMap);

        //dbilldate（单据日期）
        DataProcessUtils.handleDateField(saleOutHeadVO, "dbilldate", sdf, generalOutHeadMap);

        //approver（签字人）
        DataProcessUtils.processField(saleOutHeadVO, generalOutHeadMap, "approver");

        // creator(创建人）
        DataProcessUtils.processField(saleOutHeadVO, generalOutHeadMap, "creator");

        // cwarehouseid(仓库）
        DataProcessUtils.processField(saleOutHeadVO, generalOutHeadMap, "cwarehouseid");

        // vtrantypecode（出库类型编码）
        DataProcessUtils.getStringField(saleOutHeadVO, "vtrantypecode", generalOutHeadMap);

        // vbillcode（单据编号）
        DataProcessUtils.getStringField(saleOutHeadVO, "vbillcode", generalOutHeadMap);

        //modifier(最后修改人）
        DataProcessUtils.processField(saleOutHeadVO, generalOutHeadMap, "modifier");

        // ntotalnum(总数量）
        DataProcessUtils.getFormattedDouble(saleOutHeadVO, "ntotalnum", generalOutHeadMap);

        //ntotalweight(总重量）
        DataProcessUtils.getFormattedDouble(saleOutHeadVO, "ntotalweight", generalOutHeadMap);

        // cdptid（部门）
        DataProcessUtils.processField(saleOutHeadVO, generalOutHeadMap, "cdptid");

        // billmaker（制单人）
        DataProcessUtils.processField(saleOutHeadVO, generalOutHeadMap, "billmaker");

        //freplenishflag(销售退货）
        DataProcessUtils.getStringField(saleOutHeadVO, "freplenishflag", generalOutHeadMap);

        //modifiedtime（最后修改时间）
        DataProcessUtils.handleDateField(saleOutHeadVO, "modifiedtime", sdf, generalOutHeadMap);

        //taudittime（签字日期）
        DataProcessUtils.handleDateField(saleOutHeadVO, "taudittime", sdf, generalOutHeadMap);

        // creationtime(创建时间)
        DataProcessUtils.handleDateField(saleOutHeadVO, "creationtime", sdf, generalOutHeadMap);

        // pk_org_v(库存组织）
        DataProcessUtils.processField(saleOutHeadVO, generalOutHeadMap, "pk_org_v");

        //creceivfinorgoid（财务组织）
        DataProcessUtils.processField(saleOutHeadVO, generalOutHeadMap, "creceivfinorgoid");

        //csaleorgoid(销售组织）
        DataProcessUtils.processField(saleOutHeadVO, generalOutHeadMap, "csaleorgoid");

        // corpoid(公司）
        DataProcessUtils.processField(saleOutHeadVO, generalOutHeadMap, "corpoid");

        // ntotalvolume(总体积)
        DataProcessUtils.getFormattedDouble(saleOutHeadVO, "ntotalvolume", generalOutHeadMap);

        //ntotalpiece(总件数）
        DataProcessUtils.getFormattedDouble(saleOutHeadVO, "ntotalpiece", generalOutHeadMap);

        // vdef21（物流公司）
        DataProcessUtils.processField(saleOutHeadVO, generalOutHeadMap, "vdef21");
        JSONObject vdef21 = (JSONObject) generalOutHeadMap.get("vdef21");
        if (vdef21 != null && vdef21.get("isMap").equals(true)) {
            generalOutHeadMap.put("vdef21", vdef21.get("name"));
        } else if (vdef21 != null && vdef21.get("isMap").equals(false)) {
            generalOutHeadMap.put("vdef21", vdef21.get("value"));
        }

        // vdef26（出库单号）
        DataProcessUtils.getStringField(saleOutHeadVO, "vdef26", generalOutHeadMap);

        // vdef10 客户收货地址（仓库地址）
        DataProcessUtils.getStringField(saleOutHeadVO, "vdef10", generalOutHeadMap);

        // vdef47 客户收货
        DataProcessUtils.processField(saleOutHeadVO, generalOutHeadMap, "vdef47");

        // vdef7
        DataProcessUtils.getStringField(saleOutHeadVO, "vdef7", generalOutHeadMap);

        // vdef8
        DataProcessUtils.getStringField(saleOutHeadVO, "vdef8", generalOutHeadMap);

        return generalOutHeadMap;

    }

    /**
     * 解析ic.SaleOutBodyVO
     *
     * @param jsonObject JSONObject实体类
     * @return 解析后的数据
     */
    private Map<String, Object> parsingsaleOutBodVO(JSONObject jsonObject) {
        HashMap<String, Object> saleOutBodyVOMap = new HashMap<>(16);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        // dproducedate(生产日期)
        DataProcessUtils.handleDateField(jsonObject, "dproducedate", sdf, saleOutBodyVOMap);

        //casscustid(客户）
        DataProcessUtils.processField(jsonObject, saleOutBodyVOMap, "casscustid");

        //csourcetranstype(来源单类型）
        DataProcessUtils.getStringField(jsonObject, "csourcetranstype", saleOutBodyVOMap);

        //nshouldassistnum(应发数量）
        DataProcessUtils.getFormattedDouble(jsonObject, "nshouldassistnum", saleOutBodyVOMap);

        //cbodytranstypecode(出库类型编码）
        DataProcessUtils.getStringField(jsonObject, "cbodytranstypecode", saleOutBodyVOMap);

        //vsourcerowno（来源单据行号）
        DataProcessUtils.getStringField(jsonObject, "vsourcerowno", saleOutBodyVOMap);

        // bbarcodeclose（是否条码关闭）
        DataProcessUtils.getStringField(jsonObject, "bbarcodeclose", saleOutBodyVOMap);


        // nnum（实发数量）
        DataProcessUtils.getFormattedDouble(jsonObject, "nnum", saleOutBodyVOMap);

        // dbizdate（出库日期）
        DataProcessUtils.handleDateField(jsonObject, "dbizdate", sdf, saleOutBodyVOMap);

        // ts
        DataProcessUtils.handleDateField(jsonObject, "ts", sdf, saleOutBodyVOMap);

        // cgeneralhid(表头主键）
        DataProcessUtils.getStringField(jsonObject, "cgeneralhid", saleOutBodyVOMap);

        // cstateid（库存状态）
        DataProcessUtils.getStringField(jsonObject, "cstateid", saleOutBodyVOMap);

        // pk_batchcode(批次主键）
        DataProcessUtils.getStringField(jsonObject, "pk_batchcode", saleOutBodyVOMap);

        //cgeneralbid（表体主键）
        DataProcessUtils.getStringField(jsonObject, "cgeneralbid", saleOutBodyVOMap);

        // nassistnum(实发数量）
        DataProcessUtils.getFormattedDouble(jsonObject, "nassistnum", saleOutBodyVOMap);

        //nshouldnum(应发主数量）
        DataProcessUtils.getFormattedDouble(jsonObject, "nshouldnum", saleOutBodyVOMap);

        // castunitid（单位）
        DataProcessUtils.processField(jsonObject, saleOutBodyVOMap, "castunitid");

        //cunitid（主单位）
        DataProcessUtils.processField(jsonObject, saleOutBodyVOMap, "cunitid");

        // bonroadflag(是否在途）
        DataProcessUtils.getStringField(jsonObject, "bonroadflag", saleOutBodyVOMap);

        // dvalidate（失效日期）
        DataProcessUtils.handleDateField(jsonObject, "dvalidate", sdf, saleOutBodyVOMap);

        //cbodywarehouseid（库存仓库）
        DataProcessUtils.processField(jsonObject, saleOutBodyVOMap, "cbodywarehouseid");

        // cmaterialvid(物料信息）
        DataProcessUtils.processField(jsonObject, saleOutBodyVOMap, "cmaterialvid");
        @SuppressWarnings("unchecked") HashMap<String, Object> pkMaterial = (HashMap<String, Object>) saleOutBodyVOMap.get("cmaterialvid");

        // 查询物料的其他信息（保质期管理、批次管理、保质期单位、保质期）
        String pk = pkMaterial.get("pk").toString();
        HashMap<String, Object> additionMap = wareHouseInventoryMapper.selectAdditionalManagement(pk);
        saleOutBodyVOMap.put("additionMap", additionMap);

        // pk_org_v（库存组织）
        DataProcessUtils.processField(jsonObject, saleOutBodyVOMap, "pk_org_v");

        //cproductorid（生产厂商）
        DataProcessUtils.processField(jsonObject, saleOutBodyVOMap, "cproductorid");

        // vchangerate（换算率）
        DataProcessUtils.getStringField(jsonObject, "vchangerate", saleOutBodyVOMap);

        // crowno（行号）
        DataProcessUtils.getStringField(jsonObject, "crowno", saleOutBodyVOMap);

        // vbatchcode（批次号）
        DataProcessUtils.getStringField(jsonObject, "vbatchcode", saleOutBodyVOMap);

        //nvolume(体积）
        DataProcessUtils.getFormattedDouble(jsonObject, "nvolume", saleOutBodyVOMap);

        //nweight(重量）
        DataProcessUtils.getFormattedDouble(jsonObject, "nweight", saleOutBodyVOMap);

        //cfirstbilldate(首次出库日期）
        DataProcessUtils.handleDateField(jsonObject, "cfirstbilldate", sdf, saleOutBodyVOMap);

        // nitemdiscountrate（单品折扣）
        DataProcessUtils.getFormattedDouble(jsonObject, "nitemdiscountrate", saleOutBodyVOMap);

        // norigtaxprice（主含税单价）
        DataProcessUtils.getFormattedDouble(jsonObject, "norigtaxprice", saleOutBodyVOMap);

        // norigtaxmny（价税合计）
        DataProcessUtils.getFormattedDouble(jsonObject, "norigtaxmny", saleOutBodyVOMap);

        // nmny（本币无税金额）
        DataProcessUtils.getFormattedDouble(jsonObject, "nmny", saleOutBodyVOMap);

        // ntaxmny（本币价税合计）
        DataProcessUtils.getFormattedDouble(jsonObject, "ntaxmny", saleOutBodyVOMap);

        // ntax（税额）
        DataProcessUtils.getFormattedDouble(jsonObject, "ntax", saleOutBodyVOMap);

        // cmaterialoid（物料）
        DataProcessUtils.processField(jsonObject, saleOutBodyVOMap, "cmaterialoid");

        // cmaterialvid.vapprovalnumber_148（批准文号）
        String vapprovalnumber148 = jsonObject.getString("cmaterialvid.vapprovalnumber_148");
        saleOutBodyVOMap.put("vapprovalnumber_148", vapprovalnumber148 == null ? "" : vapprovalnumber148);

        // cmaterialvid.cholder_148(注册人持有人）
        DataProcessUtils.processField(jsonObject, saleOutBodyVOMap, "cmaterialvid.cholder_148");
        if (saleOutBodyVOMap.get("cmaterialvid.cholder_148") != null) {
            Object cholder148 = saleOutBodyVOMap.get("cmaterialvid.cholder_148");
            saleOutBodyVOMap.remove("cmaterialvid.cholder_148");
            saleOutBodyVOMap.put("cholder_148", cholder148);
        }

        // cmaterialvid.vmanufacturer_148(生产厂商）)
        DataProcessUtils.processField(jsonObject, saleOutBodyVOMap, "cmaterialvid.vmanufacturer_148");
        if (saleOutBodyVOMap.get("cmaterialvid.vmanufacturer_148") != null) {
            Object vmanufacturer148 = saleOutBodyVOMap.get("cmaterialvid.vmanufacturer_148");
            saleOutBodyVOMap.remove("cmaterialvid.vmanufacturer_148");
            saleOutBodyVOMap.put("vmanufacturer_148", vmanufacturer148);
        }

        // vbcdef1（合箱说明）
        DataProcessUtils.getStringField(jsonObject, "vbcdef1", saleOutBodyVOMap);

        // vbdef48（复验期）
        DataProcessUtils.getStringField(jsonObject, "vbdef48", saleOutBodyVOMap);

        return saleOutBodyVOMap;
    }

}
